﻿using SecurityClient;
using SecurityInterface;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SecurityModule
{
    /// <summary>
    /// A utility class to help break collection calls to Security Service into several chuncks so it doesn't exceed the limit of message size.
    /// </summary>
    public static class ChunkArrayOperation
    {
        /// <summary>
        /// Breaks 1 call to <see cref="SecurityServiceProxy.BulkEncrypt"/> into many, each with max <paramref name="chunkSize"/>.
        /// </summary>
        /// <param name="security"><see cref="SecurityServiceProxy"/> object to use.</param>
        /// <param name="data">Plain data to be encrypted.</param>
        /// <param name="chunkSize">The maximum number of values to be sent per a single call.</param>
        /// <returns>A single <see cref="BulkEncryptResult"/> containing all values, all calls must succeeded or else it is considered to have failed.</returns>
        public static BulkEncryptResult BulkEncryptInChuncks(SecurityServiceProxy security, decimal[] data, int chunkSize)
        {
            if (chunkSize <= 0)
                throw new ArgumentException("Value must be positive", "chunkSize");
            var result = new List<string>();
            var chunkNumber = 0;
            var chunkData = data.Take(chunkSize).ToArray();
            var partialResult = new BulkEncryptResult();
            while (chunkData.Length > 0)
            {
                partialResult = security.BulkEncrypt(chunkData);
                if (partialResult.Success)
                {
                    result.AddRange(partialResult.EncryptedValues);
                }
                else
                {
                    return new BulkEncryptResult
                    {
                        EncryptedValues = null,
                        ErrorMessage = partialResult.ErrorMessage,
                        Success = false,
                        SecureSessionId = partialResult.SecureSessionId
                    };
                }
                chunkNumber++;
                chunkData = data.Skip(chunkNumber * chunkSize).Take(chunkSize).ToArray();
            }
            return new BulkEncryptResult
                    {
                        EncryptedValues = result.ToArray(),
                        ErrorMessage = null,
                        Success = true,
                        SecureSessionId = partialResult.SecureSessionId
                    };
        }

        /// <summary>
        /// Breaks 1 call to <see cref="SecurityServiceProxy.BulkDecrypt"/> into many, each with max <paramref name="chunkSize"/>.
        /// </summary>
        /// <param name="security"><see cref="SecurityServiceProxy"/> object to use.</param>
        /// <param name="data">Encrypted data to be decrypted.</param>
        /// <param name="chunkSize">The maximum number of values to be sent per a single call.</param>
        /// <returns>A single <see cref="BulkDecryptResult"/> containing all values, all calls must succeeded or else it is considered to have failed.</returns>
        public static BulkDecryptResult BulkDecryptInChuncks(SecurityServiceProxy security, string[] data, int chunkSize)
        {
            if (chunkSize <= 0)
                throw new ArgumentException("Value must be positive", "chunkSize");
            var result = new List<decimal>();
            var chunkNumber = 0;
            var chunkData = data.Take(chunkSize).ToArray();
            var partialResult = new BulkDecryptResult();
            while (chunkData.Length > 0)
            {
                partialResult = security.BulkDecrypt(chunkData);
                if (partialResult.Success)
                {
                    result.AddRange(partialResult.Values);
                }
                else
                {
                    return new BulkDecryptResult
                    {
                        Values = null,
                        ErrorMessage = partialResult.ErrorMessage,
                        Success = false,
                        SecureSessionId = partialResult.SecureSessionId
                    };
                }
                chunkNumber++;
                chunkData = data.Skip(chunkNumber * chunkSize).Take(chunkSize).ToArray();
            }
            return new BulkDecryptResult
            {
                Values = result.ToArray(),
                ErrorMessage = null,
                Success = true,
                SecureSessionId = partialResult.SecureSessionId
            };
        }
    }
}
